package cn.ibobo.lease.app.controller;

import cn.ibobo.lease.app.service.UserBalanceService;
import cn.ibobo.lease.common.enums.ResultEnum;
import cn.ibobo.lease.common.util.Constant;
import cn.ibobo.lease.common.util.Md5Util;
import cn.ibobo.lease.common.util.ResultVOUtil;
import cn.ibobo.lease.common.util.UuidUtil;
import cn.ibobo.lease.common.vo.PayVO;
import cn.ibobo.lease.common.vo.ResultVO;
import cn.ibobo.lease.common.vo.UserVO;
import com.alibaba.fastjson.JSON;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import weixin.popular.api.PayMchAPI;
import weixin.popular.bean.paymch.SandboxSignkey;
import weixin.popular.bean.paymch.Unifiedorder;
import weixin.popular.bean.paymch.UnifiedorderResult;
import weixin.popular.util.SignatureUtil;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.*;

/**
 * @Description 微信支付
 * @Author lililiang
 * @Date 2019/1/28 14:24
 * @Param
 * @Return
 */
@Api(tags = "微信支付控制器")
@RestController
@RequestMapping("wPay")
public class PayController {

    @Autowired
    private ResultVOUtil<Object> resultObject;
    @Autowired
    private UserBalanceService userBalanceService;

    private static final Log LOGGER = LogFactory.getLog(PayController.class);

    /**
    　* @Description: 正式
    　* @author zhouxin
    　* @date 2019/1/3 14:52
     */
//    @PostMapping("goRefund")
//    public void goRefund(Refund refund) {
//    	try {
//			shopOrderRefundService.refund(refund);
//		} catch (Exception e) {
//
//			e.printStackTrace();
//		}
//    }

    /**
     * @Description 唤起微信支付
     * @Author lililiang
     * @Date 2019/1/28 15:32
     * @Param [entity]
     * @Return cn.ibobo.lease.common.vo.ResultVO<java.lang.Object>
     */
    @ApiOperation(value = "唤起微信支付")
    @PostMapping("goPay")
    public ResultVO<Object> goPay(PayVO entity) {
        LOGGER.info("wPay/goPay entity = " + entity.toString());
        try {
            Map<String, String> signParam = new TreeMap<String, String>();
                Unifiedorder unifiedorder = new Unifiedorder();
                unifiedorder.setBody(Constant.PAY_NAME);//显示支付主题账号或商品名称
                String wxOrderId = UuidUtil.getUuid();
                Map map = new HashMap();
                map.put("uid", entity.getUid());
                map.put("wxOrderId", wxOrderId);
                map.put("balance", entity.getBalance());
                map.put("type", "wx");
                unifiedorder.setAttach(JSON.toJSONString(map));//attach 自定义回传参数
                unifiedorder.setOut_trade_no(wxOrderId);//外部交易订单号
//                unifiedorder.setTotal_fee("1");//总费用
                unifiedorder.setTotal_fee((entity.getBalance().multiply(new BigDecimal("100"))).toString());//总费用
                unifiedorder.setNonce_str(String.valueOf(System.currentTimeMillis() / 1000));
                unifiedorder.setSpbill_create_ip(Constant.IP);
                unifiedorder.setNotify_url(Constant.NOTIFY_URL + "wPay/payBack");//设置回调地址
                String key = "";
                String originType = "app";
                // 如果发起支付来源是APP---start---
                if (!StringUtils.isEmpty(originType) && "app".equals(originType)) {
                    unifiedorder.setAppid(Constant.APP_ID);
                    unifiedorder.setMch_id(Constant.MCH_ID);
                    unifiedorder.setTrade_type("APP");
                    key = Constant.KEY;
                } else {
                    unifiedorder.setAppid(Constant.APP_ID_XCX);
                    unifiedorder.setMch_id(Constant.MCH_ID_XCX);
                    unifiedorder.setTrade_type("JSAPI");
                    key = Constant.KEY;
//                    String openid = entity.getOpenid();
                    String openid = "openid";//这里需要从前台传微信用户的openid
                    if (!StringUtils.isEmpty(openid)) {
                        unifiedorder.setOpenid(openid);
                    }
                }
                UnifiedorderResult result = PayMchAPI.payUnifiedorder(unifiedorder, key);
                String prepayId = result.getPrepay_id();
                Long currentTimeMillis = System.currentTimeMillis();
                String seconds = String.valueOf(currentTimeMillis / 1000L).substring(0, 10);
                String uuid = String.valueOf(System.currentTimeMillis() / 1000);
                // 如果发起支付来源是APP
                if (!StringUtils.isEmpty(originType) && "app".equals(originType)) {
                    signParam.put("appid", Constant.APP_ID);
                    signParam.put("partnerid", Constant.MCH_ID);
                    signParam.put("prepayid", prepayId);
                    signParam.put("package", "Sign=WXPay");
                    signParam.put("noncestr", uuid);
                    signParam.put("timestamp", seconds);
                    signParam.put("sign", SignatureUtil.generateSign(signParam,unifiedorder.getSign_type(),key));
                } else {
                    signParam.put("appId", Constant.APP_ID_XCX);
                    signParam.put("nonceStr", uuid);
                    signParam.put("package", "prepay_id="+prepayId);
                    signParam.put("timestamp", seconds);
                    String sign = Md5Util.getMd5Encode("appId=" + Constant.APP_ID_XCX + "&nonceStr=" + uuid + "&package=prepay_id="+prepayId+"&signType=MD5&timeStamp=" + seconds + "&key=" + Constant.KEY_XCX).toUpperCase();
                    signParam.put("sign", sign);
                }
                //微信支付返回值
                return resultObject.success(ResultEnum.SUCCESS.getCode(), ResultEnum.SUCCESS.getMsg(), signParam);
        } catch (Exception e) {
            LOGGER.info(e.getMessage());
            e.printStackTrace();
            return resultObject.error(ResultEnum.EXCEPTION.getCode(), ResultEnum.EXCEPTION.getMsg());
        }
    }


    /**
     * @Description 微信支付回调
     * @Author lililiang
     * @Date 2019/1/28 17:24
     * @Param [request, response]
     * @Return java.lang.String
     */
    @PostMapping("payBack")
    public String payBack(HttpServletRequest request, HttpServletResponse response) throws Exception {
        LOGGER.info("  ===============  wPay/payBack ======== ");
//        //返回给微信的处理结果
        String result;
        String inputLine;
        String notityXml = "";
        request.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");
        response.setHeader("Access-Control-Allow-Origin", "*");
        //微信返回信息
        try {
            while ((inputLine = request.getReader().readLine()) != null) {
                notityXml += inputLine;
            }
            request.getReader().close();
        } catch (Exception e) {
            e.printStackTrace();
            result = setXml("FAIL", "xml获取失败");
        }
        System.out.println(notityXml);
        Map<String, String> map = xmlToMap(notityXml);

        // 解析各种数据
        String appid = (String) map.get("appid");                  //应用ID
        String attach = (String) map.get("attach");                //商家数据包
        String bank_type = (String) map.get("bank_type");          //付款银行
        String cash_fee = (String) map.get("cash_fee");            //现金支付金额
        String fee_type = (String) map.get("fee_type");            //货币种类
        String is_subscribe = (String) map.get("is_subscribe");    //是否关注公众账号
        String mch_id = (String) map.get("mch_id");                //商户号
        String nonce_str = (String) map.get("nonce_str");          //随机字符串
        String openid = (String) map.get("openid");                //用户标识
        String out_trade_no = (String) map.get("out_trade_no");    //获取商户订单号
        String result_code = (String) map.get("result_code");      //业务结果
        String return_code = (String) map.get("return_code");      //SUCCESS/FAIL
        String sign = (String) map.get("sign");                    //获取签名
        String time_end = (String) map.get("time_end");            //支付完成时间
        String total_fee = (String) map.get("total_fee");          //获取订单金额
        String trade_type = (String) map.get("trade_type");        //交易类型
        String transaction_id = (String) map.get("transaction_id");//微信支付订单号

        SortedMap<String, String> parameters = new TreeMap<String, String>();
        parameters.put("appid", appid);
        parameters.put("attach", attach);
        parameters.put("bank_type", bank_type);
        parameters.put("cash_fee", cash_fee);
        parameters.put("fee_type", fee_type);
        parameters.put("is_subscribe", is_subscribe);
        parameters.put("mch_id", mch_id);
        parameters.put("nonce_str", nonce_str);
        parameters.put("openid", openid);
        parameters.put("out_trade_no", out_trade_no);
        parameters.put("result_code", result_code);
        parameters.put("return_code", return_code);
        parameters.put("time_end", time_end);
        parameters.put("total_fee", total_fee);
        parameters.put("trade_type", trade_type);
        parameters.put("transaction_id", transaction_id);
        String endsign = createSign("UTF-8", parameters, trade_type);

        LOGGER.info("wPay/payBack sign = " + sign + ", endsign = " + endsign);
        // 验证签名
        if (sign.equals(endsign)) {
            //这里添加业务处理类
            HashMap attachMap = JSON.parseObject(attach, HashMap.class);
            userBalanceService.balance(attachMap);
            result = setXml("SUCCESS", "OK");
        } else {
            result = setXml("FAIL", "签名不一致！");
        }
        return result;
    }

    /**
     * @Description 通过xml 返回给微信消息
     * @Author lililiang
     * @Date 2019/1/28 17:29
     * @Param [return_code, return_msg]
     * @Return java.lang.String
     */
    public String setXml(String return_code, String return_msg) {
        SortedMap<String, String> parameters = new TreeMap<String, String>();
        parameters.put("return_code", return_code);
        parameters.put("return_msg", return_msg);
        return "<xml><return_code><![CDATA[" + return_code + "]]>" + "</return_code><return_msg><![CDATA[" + return_msg + "]]></return_msg></xml>";
    }

    /**
     * @Description 获取验签秘钥
     * @Author lililiang
     * @Date 2019/1/28 17:30
     * @Param []
     * @Return java.lang.String
     */
    @PostMapping("getSignKey")
    public String getSignKey() {
        PayMchAPI.sandboxnewStart();
        String mchId = Constant.MCH_ID;
        String key = Constant.KEY;
        SandboxSignkey result = PayMchAPI.sandboxnewPayGetsignkey(mchId, key);
        System.out.println(result);
        return "ok";
    }

    /**
     * @Description 定义签名，微信根据参数字段的ASCII码值进行排序 加密签名,故使用SortMap进行参数排序
     * @Author lililiang
     * @Date 2019/1/28 17:30
     * @Param [characterEncoding, parameters, trade_type]
     * @Return java.lang.String
     */
    public static String createSign(String characterEncoding, SortedMap<String,String> parameters, String trade_type){
        StringBuffer sb = new StringBuffer();
        Set es = parameters.entrySet();
        String key = "";
        Iterator it = es.iterator();
        while(it.hasNext()) {
            Map.Entry entry = (Map.Entry)it.next();
            String k = (String)entry.getKey();
            Object v = entry.getValue();
            if(null != v && !"".equals(v)  && !"sign".equals(k) && !"key".equals(k)) {
                sb.append(k + "=" + v + "&");
            }
            if ("key".equals(k)) {
                key = (String)v;
            }
        }
        //最后加密时添加商户密钥，由于key值放在最后，所以不用添加到SortMap里面去，单独处理，编码方式采用UTF-8
        if (!StringUtils.isEmpty(trade_type) && "APP".equals(trade_type)) {
            sb.append("key=" + Constant.KEY);
        } else {
            sb.append("key=" + Constant.KEY);
        }
        String sign = DigestUtils.md5Hex(sb.toString()).toUpperCase();
        return sign;
    }

    /**
     * @Description xmlToMap
     * @Author lililiang
     * @Date 2019/1/28 17:30
     * @Param [strXML]
     * @Return java.util.Map<java.lang.String,java.lang.String>
     */
    public static Map<String, String> xmlToMap(String strXML) throws Exception {
        try {
            Map<String, String> data = new HashMap<String, String>();
            DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
            InputStream stream = new ByteArrayInputStream(strXML.getBytes("UTF-8"));
            org.w3c.dom.Document doc = documentBuilder.parse(stream);
            doc.getDocumentElement().normalize();
            NodeList nodeList = doc.getDocumentElement().getChildNodes();
            for (int idx = 0; idx < nodeList.getLength(); ++idx) {
                Node node = nodeList.item(idx);
                if (node.getNodeType() == Node.ELEMENT_NODE) {
                    org.w3c.dom.Element element = (org.w3c.dom.Element) node;
                    data.put(element.getNodeName(), element.getTextContent());
                }
            }
            try {
                stream.close();
            } catch (Exception ex) {
                // do nothing
            }
            return data;
        } catch (Exception ex) {
            throw ex;
        }

    }

}
